package com.gooseeker.modbus;

import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.TooManyListenersException;

import org.apache.log4j.Logger;

import com.gooseeker.business.MonitorService;
import com.gooseeker.util.Constants;

public class ModbusUtils /* implements SerialPortEventListener*/
{
	private Logger logger = Logger.getLogger(ModbusUtils.class);
	
	private MonitorService monitorService;
	
	public void setMonitorService(MonitorService service)
	{
		this.monitorService = service;
	}
	/**
	 * 读取的数据个数
	 */
	//private int numBytes;
	/**
	 * 接收缓冲区
	 */
	//private static byte[] readBuffer = new byte[1024];
	/**
	 * 接收流句柄
	 */
	private static InputStream inputStream;
	/**
	 * 发送流句柄
	 */
	private static OutputStream outputStream;
	/**
	 * 已打开的串口
	 */
	static SerialPort serialPort;
	/**
	 * 串口打开标记
	 */
	private boolean openFlag = false;
	
	private SerialPortRecvImpl dataRecvImpl = null;
	
	private static ModbusUtils theInstance = null;
	
	public static ModbusUtils getInstance()
	{
		if (null == theInstance)
		{
			synchronized (ModbusUtils.class)
			{
				if (null == theInstance)
				{
					theInstance = new ModbusUtils();
				}
			}
		}
		
		return theInstance;
	}

	private ModbusUtils()
	{
		openFlag = false;
	}

	public boolean isOpen()
	{
		return openFlag;
	}
	
	public void open(String port)
	{
		if (openFlag)
		{
			close();
		}
		try
		{
			CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(port);
			serialPort = (SerialPort) portId.open("SerialReader",Constants.DEFAULT_OPEN_TIMEOUT);
			
			inputStream = serialPort.getInputStream();
			outputStream = serialPort.getOutputStream();
			
			if (null == dataRecvImpl)
			{
				dataRecvImpl = new SerialPortRecvImpl(inputStream,monitorService);
			}
			serialPort.addEventListener(dataRecvImpl);
			//serialPort.addEventListener(this);
			serialPort.notifyOnDataAvailable(true);
			serialPort.setSerialPortParams(Constants.DEFAULT_COM_BUAD_RATE,
					Constants.DEFAULT_COM_DATA_BIT, Constants.DEFAULT_COM_STOP_BIT,
					Constants.DEFAULT_COM_PARITY);

			openFlag = true;
			logger.info(port + "打开成功, buad=" + Constants.DEFAULT_COM_BUAD_RATE);
			System.out.println("串口打开成功");
		} catch (PortInUseException e)
		{
			logger.error(port + "端口被占用");
			System.out.println("端口被占用");
		} catch (TooManyListenersException e)
		{
			logger.error(port + "监听者过多");
			System.out.println("监听者过多");
		} catch (UnsupportedCommOperationException e)
		{
			logger.error(port + "端口操作命令不支持");
			System.out.println("端口操作命令不支持");
		} catch (NoSuchPortException e)
		{
			logger.error(port + "端口不存在");
			System.out.println("端口不存在");
		} catch (IOException e)
		{
			logger.error(port + "串口打开失败");
			System.out.println("串口打开失败");
		}
	}

	public void send(byte[] cmd)
	{
		if (cmd == null)
		{
			logger.error("设备地址不能为0");
			return;
		}
		
		// outputStream = serialPort.getOutputStream();

		// 发指令到串口
		
		try 
		{
			outputStream.write(cmd);
			outputStream.flush();
		} catch (IOException e) {
			logger.error("命令发送失败: " + e.getMessage());
		}
		
	}

	public void close()
	{
		if (openFlag)
		{
			try
			{
				serialPort.notifyOnDataAvailable(false);
				serialPort.removeEventListener();
				inputStream.close();
				outputStream.close();
				serialPort.close();
				openFlag = false;
				dataRecvImpl = null;
			} catch (IOException ex)
			{
				logger.error("串口关闭失败");
				System.out.println("关闭失败");
			}
		}
	}
	/*
	public void serialEvent(SerialPortEvent event)
	{
		try
		{
			// 端口读入数据事件触发后,等待n毫秒后再读取,以便让数据一次性读完
			Thread.sleep(DELAY_READ_DATA);
		} catch (InterruptedException e)
		{
			e.printStackTrace();
		}

		switch (event.getEventType())
		{
		case SerialPortEvent.BI: // 10
		case SerialPortEvent.OE: // 7
		case SerialPortEvent.FE: // 9
		case SerialPortEvent.PE: // 8
		case SerialPortEvent.CD: // 6
		case SerialPortEvent.CTS: // 3
		case SerialPortEvent.DSR: // 4
		case SerialPortEvent.RI: // 5
		case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2
			break;
		case SerialPortEvent.DATA_AVAILABLE: // 1
			try
			{
				// 有数据可读
				while (inputStream.available() > 0)
				{
					numBytes = inputStream.read(readBuffer);
				}

				for (int i = 0; i < numBytes; i++)
				{
					System.out.printf("%02x ", readBuffer[i] & 0xff);
				}
				
				System.out.println();
				
				changeMessage(readBuffer, numBytes);
			} catch (IOException e)
			{
				e.printStackTrace();
			}
			break;
		}
	}
	*/

//	public static void main(String[] args)
//	{
//		ModbusUtils mo = new ModbusUtils();
//		mo.listPorts();
//		mo.open(Constants.DEFAULT_COM_PORT);
//		byte[] cmd = CRC16Utils.modbusCrc16("01 04 00 00 00 02");
//		mo.send(cmd);
//
//		while (true)
//		{
//			try
//			{
//				Thread.sleep(1000);
//			} catch (InterruptedException e)
//			{
//				e.printStackTrace();
//			}
//
//			mo.send(cmd);
//		}
//	}
}
